#include "objloader.h"
#include <GL/glut.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cmath>

ObjLoader::ObjLoader(string filename) {

    cout << "Loading:" << filename << endl;

    string line;
    fstream f;
    f.open(filename, ios::in);
    if (!f.is_open()) {
        cout << "Something Went Wrong When Opening Objfiles" << endl;
    }

    while (!f.eof()) {
        getline(f, line); //拿到obj文件中一行，作为一个字符串
        vector<string> parameters;
        string tailMark = " ";
        string ans = "";

        line = line.append(tailMark);
        bool ifbeforeblock = false;
        for (std::__cxx11::basic_string<char>::size_type i = 0; i < line.length(); i++) {
            char ch = line[i];

            if (ch != ' ') {
                ans += ch;
                ifbeforeblock = false;
            } else {
                if (!ifbeforeblock) {
                    parameters.push_back(ans); //取出字符串中的元素，以空格切分
                    ans = "";
                    ifbeforeblock = true;
                }
            }
        }

        if (parameters[0] == "v") { //如果是顶点的话
            vector<GLfloat> Point;
            for (int i = 1; i < 4;
                 i++) { //从1开始，将顶点的xyz三个坐标放入顶点vector
                GLfloat xyz = atof(parameters[i].c_str());
                Point.push_back(xyz);
            }
            vSets.push_back(Point);
            // cout << parameters[0] << " " << parameters[1] << " " <<
            // parameters[2] <<" "<< parameters[3]  << endl;
        }

        else if (parameters[0] == "vt") {
            vector<GLfloat> Point;
            for (int i = 1; i < 3;
                 i++) { //从1开始，将顶点的xyz三个坐标放入顶点vector
                GLfloat xyz = atof(parameters[i].c_str());
                Point.push_back(xyz);
            }
            vtSets.push_back(Point);
            // cout << parameters[0] << " " << parameters[1] << " " <<
            // parameters[2] << endl;
        }

        else if (parameters[0] == "vn") {
            vector<GLfloat> Point;
            for (int i = 1; i < 4; i++) { //从1开始，将xy坐标放入顶点vector
                GLfloat xyz = atof(parameters[i].c_str());
                Point.push_back(xyz);
            }
            vnSets.push_back(Point);
            // cout << parameters[0] << " " << parameters[1] << " " <<
            // parameters[2] << " " << parameters[3] << endl;
        }

        else if (parameters[0] == "f") { //如果是面的话，存放三个顶点的索引
            //三角形面的obj文件
            if (parameters.size() == 4) {
                vector<fpoint> vIndexSets;
                for (std::__cxx11::basic_string<char>::size_type i = 1; i < 4; i++) {
                    string x = parameters[i];
                    string ans[3] = {"", "", ""};
                    int number = 0; //表示读取的是v，vn，vt中的哪一个
                    for (std::__cxx11::basic_string<char>::size_type j = 0; j < x.length(); j++) { //跳过‘/’
                        char ch = x[j];
                        if (ch != '/') {
                            ans[number] += ch;
                        } else {
                            number++;
                        }
                    }
                    fpoint index;
                    index.v = atof(ans[0].c_str()) - 1;
                    index.vt = atof(ans[1].c_str()) - 1;
                    index.vn = atof(ans[2].c_str()) - 1;
                    //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                    vIndexSets.push_back(index);
                }
                fSets.push_back(vIndexSets);
                // cout <<parameters.size()<< parameters[0] << " " <<
                // parameters[1] << " " << parameters[2] << " " << parameters[3]
                // << endl;
            }
            //四边形面的obj文件
            else if (parameters.size() > 4) {
                //第一个三角形面
                vector<fpoint> vIndexSets1;

                // point1
                string x1 = parameters[1];
                string ans1[3] = {"", "", ""};
                int n1 = 0; //表示读取的是v，vn，vt中的哪一个
                for (std::__cxx11::basic_string<char>::size_type j = 0; j < x1.length(); j++) { //跳过‘/’
                    char ch1 = x1[j];
                    if (ch1 != '/') {
                        ans1[n1] += ch1;
                    } else {
                        n1++;
                    }
                }
                fpoint index1;
                index1.v = atof(ans1[0].c_str()) - 1;
                index1.vt = atof(ans1[1].c_str()) - 1;
                index1.vn = atof(ans1[2].c_str()) - 1;
                //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                vIndexSets1.push_back(index1);

                // point2
                string x2 = parameters[2];
                string ans2[3] = {"", "", ""};
                int n2 = 0; //表示读取的是v，vn，vt中的哪一个
                for (std::__cxx11::basic_string<char>::size_type j = 0; j < x2.length(); j++) { //跳过‘/’
                    char ch2 = x2[j];
                    if (ch2 != '/') {
                        ans2[n2] += ch2;
                    } else {
                        n2++;
                    }
                }
                fpoint index2;
                index2.v = atof(ans2[0].c_str()) - 1;
                index2.vt = atof(ans2[1].c_str()) - 1;
                index2.vn = atof(ans2[2].c_str()) - 1;
                //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                vIndexSets1.push_back(index2);

                // point3
                string x3 = parameters[3];
                string ans3[3] = {"", "", ""};
                int n3 = 0; //表示读取的是v，vn，vt中的哪一个
                for (std::__cxx11::basic_string<char>::size_type j = 0; j < x3.length(); j++) { //跳过‘/’
                    char ch3 = x3[j];
                    if (ch3 != '/') {
                        ans3[n3] += ch3;
                    } else {
                        n3++;
                    }
                }
                fpoint index3;
                index3.v = atof(ans3[0].c_str()) - 1;
                index3.vt = atof(ans3[1].c_str()) - 1;
                index3.vn = atof(ans3[2].c_str()) - 1;
                //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                vIndexSets1.push_back(index3);

                fSets.push_back(vIndexSets1);

                //第二个三角形面
                vector<fpoint> vIndexSets2;

                // point1
                string x4 = parameters[1];
                string ans4[3] = {"", "", ""};
                int n4 = 0; //表示读取的是v，vn，vt中的哪一个
                for (std::__cxx11::basic_string<char>::size_type j = 0; j < x4.length(); j++) { //跳过‘/’
                    char ch4 = x4[j];
                    if (ch4 != '/') {
                        ans4[n4] += ch4;
                    } else {
                        n4++;
                    }
                }
                fpoint index4;
                index4.v = atof(ans4[0].c_str()) - 1;
                index4.vt = atof(ans4[1].c_str()) - 1;
                index4.vn = atof(ans4[2].c_str()) - 1;
                //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                vIndexSets2.push_back(index4);

                // point2
                string x5 = parameters[3];
                string ans5[3] = {"", "", ""};
                int n5 = 0; //表示读取的是v，vn，vt中的哪一个
                for (std::__cxx11::basic_string<char>::size_type j = 0; j < x5.length(); j++) { //跳过‘/’
                    char ch5 = x5[j];
                    if (ch5 != '/') {
                        ans5[n5] += ch5;
                    } else {
                        n5++;
                    }
                }
                fpoint index5;
                index5.v = atof(ans5[0].c_str()) - 1;
                index5.vt = atof(ans5[1].c_str()) - 1;
                index5.vn = atof(ans5[2].c_str()) - 1;
                //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                vIndexSets2.push_back(index5);

                // point3
                string x6 = parameters[4];
                string ans6[3] = {"", "", ""};
                int n6 = 0; //表示读取的是v，vn，vt中的哪一个
                for (std::__cxx11::basic_string<char>::size_type j = 0; j < x6.length(); j++) { //跳过‘/’
                    char ch6 = x6[j];
                    if (ch6 != '/') {
                        ans6[n6] += ch6;
                    } else {
                        n6++;
                    }
                }
                fpoint index6;
                index6.v = atof(ans6[0].c_str()) - 1;
                index6.vt = atof(ans6[1].c_str()) - 1;
                index6.vn = atof(ans6[2].c_str()) - 1;
                //因为顶点索引在obj文件中是从1开始的，而我们存放的顶点vector是从0开始的，因此要减1
                vIndexSets2.push_back(index6);

                fSets.push_back(vIndexSets2);

                // cout << parameters.size() << parameters[0] << " " <<
                // parameters[1] << " " << parameters[2] << " " << parameters[3]
                // << " " <<parameters[4] << " " << endl;
            }
        }
    }
    f.close();
    cout << "Loading complete" << endl;
}

void ObjLoader::Draw() {

    glBegin(GL_TRIANGLES); //开始绘制
    for (std::__cxx11::basic_string<char>::size_type i = 0; i < fSets.size(); i++) {
        GLfloat VN[3];
        //三个顶点
        GLfloat SV1[3], VN1[3], VT1[2] = {0, 0};
        GLfloat SV2[3], VN2[3], VT2[2] = {0, 0};
        GLfloat SV3[3], VN3[3], VT3[2] = {0, 0};

        if ((fSets[i]).size() != 3) {
            cout << "the fSetsets_Size is not correct" << endl;
        } else {
            GLint firstVertexIndex = (fSets[i])[0].v; //取出顶点索引
            GLint secondVertexIndex = (fSets[i])[1].v;
            GLint thirdVertexIndex = (fSets[i])[2].v;

            SV1[0] = (vSets[firstVertexIndex])[0]; //第一个顶点
            SV1[1] = (vSets[firstVertexIndex])[1];
            SV1[2] = (vSets[firstVertexIndex])[2];

            SV2[0] = (vSets[secondVertexIndex])[0]; //第二个顶点
            SV2[1] = (vSets[secondVertexIndex])[1];
            SV2[2] = (vSets[secondVertexIndex])[2];

            SV3[0] = (vSets[thirdVertexIndex])[0]; //第三个顶点
            SV3[1] = (vSets[thirdVertexIndex])[1];
            SV3[2] = (vSets[thirdVertexIndex])[2];

            if ((fSets[i])[0].vn != -1 && (fSets[i])[1].vn != -1 &&
                (fSets[i])[2].vn != -1) {
                VN1[0] = (vnSets[(fSets[i])[0].vn])[0]; //第一个顶点法向量
                VN1[1] = (vnSets[(fSets[i])[0].vn])[1];
                VN1[2] = (vnSets[(fSets[i])[0].vn])[2];

                VN2[0] = (vnSets[(fSets[i])[1].vn])[0]; //
                VN2[1] = (vnSets[(fSets[i])[1].vn])[1];
                VN2[2] = (vnSets[(fSets[i])[1].vn])[2];

                VN3[0] = (vnSets[(fSets[i])[2].vn])[0]; //
                VN3[1] = (vnSets[(fSets[i])[2].vn])[1];
                VN3[2] = (vnSets[(fSets[i])[2].vn])[2];

                VN[0] = VN1[0] + VN2[0] + VN3[0];
                VN[1] = VN1[1] + VN2[1] + VN3[1];
                VN[2] = VN1[2] + VN2[2] + VN3[2];
            } else {
                GLfloat vec1[3], vec2[3], vec3[3]; //计算法向量
                //(x2-x1,y2-y1,z2-z1)
                vec1[0] = SV1[0] - SV2[0];
                vec1[1] = SV1[1] - SV2[1];
                vec1[2] = SV1[2] - SV2[2];

                //(x3-x2,y3-y2,z3-z2)
                vec2[0] = SV1[0] - SV3[0];
                vec2[1] = SV1[1] - SV3[1];
                vec2[2] = SV1[2] - SV3[2];

                //(x3-x1,y3-y1,z3-z1)
                vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
                vec3[1] = vec2[0] * vec1[2] - vec2[2] * vec1[0];
                vec3[2] = vec2[1] * vec1[0] - vec2[0] * vec1[1];

                GLfloat D =
                    sqrt(pow(vec3[0], 2) + pow(vec3[1], 2) + pow(vec3[2], 2));

                VN[0] = vec3[0] / D;
                VN[1] = vec3[1] / D;
                VN[2] = vec3[2] / D;
            }

            if ((fSets[i])[0].vt != -1 && (fSets[i])[1].vt != -1) {

                VT1[0] = (vtSets[(fSets[i])[0].vt])[0]; //第一个顶点纹理
                VT1[1] = (vtSets[(fSets[i])[0].vt])[1];

                VT2[0] = (vtSets[(fSets[i])[1].vt])[0]; //
                VT2[1] = (vtSets[(fSets[i])[1].vt])[1];

                VT3[0] = (vtSets[(fSets[i])[2].vt])[0]; //
                VT3[1] = (vtSets[(fSets[i])[2].vt])[1];
            }

            glNormal3f(VN[0], VN[1], VN[2]); //绘制法向量

            glTexCoord2f(VT1[0], VT1[1]);
            glVertex3f(SV1[0], SV1[1], SV1[2]); //绘制三角面片
            glTexCoord2f(VT2[0], VT2[1]);
            glVertex3f(SV2[0], SV2[1], SV2[2]);
            glTexCoord2f(VT3[0], VT3[1]);
            glVertex3f(SV3[0], SV3[1], SV3[2]);
            // cout << SV1[0]<<" " << SV1[1] << " " << SV1[2] << endl;
        }
    }
    glEnd();
    // cout << "draw complete" << endl;
}